package utils

import (
	"io"
	"sync"
	"sync/atomic"
)

type IOTrans struct {
	io1_size int64
	io2_size int64
	dis_flag int32
	reason   string
	io1      io.ReadWriteCloser
	io2      io.ReadWriteCloser
}

func NewIOTrans() *IOTrans {
	rval := &IOTrans{}
	return rval
}

func (this *IOTrans) IO1Size() int64 {
	return this.io1_size
}

func (this *IOTrans) IO2Size() int64 {
	return this.io1_size
}

func (this *IOTrans) Disreason() string {
	return this.reason
}

func (this *IOTrans) SetIO1(v io.ReadWriteCloser) {
	this.io1 = v
}

func (this *IOTrans) SetIO2(v io.ReadWriteCloser) {
	this.io2 = v
}

func (this *IOTrans) Release() {
	this.io1 = nil
	this.io2 = nil
}

func (this *IOTrans) RequestDisconnect(reason string) {
	if atomic.CompareAndSwapInt32(&this.dis_flag, 0, 1) {
		this.reason = reason
	}
	if this.io1 != nil {
		this.io1.Close()
	}
	if this.io2 != nil {
		this.io2.Close()
	}
}

func (this *IOTrans) ExecTrans() {
	this.dis_flag = 0
	if this.io1 == nil || this.io2 == nil {
		return
	}

	wait := new(sync.WaitGroup)
	wait.Add(1)
	go DoIoCopy(this.io1, this.io2, &this.io2_size, func(err error, tag io.ReadWriteCloser) {
		this.RequestDisconnect(err.Error())
	}, func() {
		wait.Done()
	}, func() []byte {
		return make([]byte, 1024)
	}, func(buf []byte) {
	})

	wait.Add(1)
	go DoIoCopy(this.io2, this.io1, &this.io1_size, func(err error, tag io.ReadWriteCloser) {
		this.RequestDisconnect(err.Error())
	}, func() {
		wait.Done()
	}, func() []byte {
		return make([]byte, 1024)
	}, func(buf []byte) {
	})
	wait.Wait()
}
